home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / GetZoneList / GetZoneList.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-18  |  25.1 KB  |  923 lines  |  [TEXT/MPS ]

  1. /* ------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    AppleTalk GetZoneList Sample Application
  6. #
  7. #    GetZoneList
  8. #
  9. #    GetZoneList.c    -    C Source
  10. #
  11. #    Copyright © 1988-90 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    1.00                November 1988
  15. #                1.01                October 1989
  16. #                1.02                May 1990
  17. #                1.03                June 1992
  18. #                1.04                July 1992
  19. #
  20. #    Components:    GetZoneList.c        May 1, 1990
  21. #                GetZoneList.p        May 1, 1990
  22. #                GetZoneList.r        May 1, 1990
  23. #                MakeFile            May 1, 1990
  24. #                UFailure.a            November 1, 1988
  25. #                UFailure.h            November 1, 1988
  26. #                UFailure.inc1.p        November 1, 1988
  27. #                UFailure.p            November 1, 1988
  28. #
  29. #    GetZoneList is a sample application that uses
  30. #    AppleTalk ATP and ZIP to obtain a list of zones
  31. #    on an AppleTalk internet.
  32. #
  33. #    GetZoneList also demonstrates using a signal, or
  34. #    failure-catching mechanism to recover from error
  35. #    situations.  Since C does not allow nested procedures
  36. #    a la Pascal, a few modifications were made to incorporate
  37. #    the failure handling and keep this sample fairly close in
  38. #    design to the Pascal sample.
  39. #    (Gee, thanks a lot M2 for using nested procs. - pvh)
  40. #
  41. #    GetZoneList is based on DTS Sample.c. For more
  42. #    description and explanation of the non-example
  43. #    specific areas of this application, please refer to
  44. #    either Sample.p or TESample.c.
  45. #
  46. ------------------------------------------------------------------------------ */
  47.  
  48. #include <Limits.h>
  49. #include <Types.h>
  50. #include <QuickDraw.h>
  51. #include <Fonts.h>
  52. #include <Events.h>
  53. #include <Controls.h>
  54. #include <Windows.h>
  55. #include <Menus.h>
  56. #include <TextEdit.h>
  57. #include <Dialogs.h>
  58. #include <Packages.h>
  59. #include <Menus.h>
  60. #include <Devices.h>
  61. #include <Events.h>
  62. #include <Scrap.h>
  63. #include <Lists.h>
  64. #include <ToolUtils.h>
  65. #include <Memory.h>
  66. #include <SegLoad.h>
  67. #include <Errors.h>
  68. #include <Files.h>
  69. #include <OSUtils.h>
  70. #include <AppleTalk.h>
  71. #include <Traps.h>
  72. #include <DiskInit.h>
  73. #include <Script.h>
  74. #include <UFailure.h>
  75.  
  76.  
  77. typedef XCallParam *XCallParamPtr;
  78.  
  79. #define        kSysEnvironsVersion        1
  80. #define        kOSEvent                app4Evt        /* event used by Multifinder */
  81. #define        kSuspendResumeMessage    1            /* high byte of suspend/resume event message */
  82. #define        kResumeMask                1            /* bit of message field for resume vs. suspend */
  83.  
  84. #define        kCR                        13            /* carriage return character */
  85. #define        kENTER                    3            /* enter character */
  86. #define        kScrollBarWidth            15            /* the width of the scrollbar in the list */
  87. #define        kListInset                -1            /* adjustment for list frame */
  88. #define        kATPTimeOutVal            3            /* re-try ATP SendRequest every 3 seconds */
  89. #define        kATPRetryCount            5            /* for five times */
  90. #define        kZonesSize                578            /* size of buffer for zone names */
  91. #define        kGZLCall                0x08000000    /* GetZoneList indicator */
  92. #define        kZIPSocket                6            /* the Zone Information Protocol socket */
  93. #define        kMoreZones                0xFF000000     /* mask to see if more zones to come */
  94. #define        kZoneCount                0x0000FFFF     /* mask to count zones in buffer */
  95. #define        kHilite                    1            /* hilite value for button control */
  96. #define        kDeHilite                0            /* dehilite value for button control */
  97. #define        kHiliteDelay            8            /* time in ticks to leave button hilited */
  98.  
  99. #define        kMinHeap                (29 * 1024)
  100. #define        kMinSpace                (20 * 1024)
  101.  
  102. #define        sErrStrings                128            /* error string STR# */
  103. #define        eStandardErr            1
  104. #define        eWrongMachine            2
  105. #define        eSmallSize                3
  106. #define        eNoMemory                4
  107. #define        eAppleTalk                5
  108. #define        eNoZones                6
  109.  
  110. #define        rAboutAlert                128            /* about alert */
  111. #define        rZoneDialog                129            /* zone list dialog */
  112. #define        dZoneList                2            /* user item that is zone list */
  113. #define        dDefault                3            /* user item that is default indicator */
  114. #define        rUserAlert                130            /* error alert */
  115.  
  116. #define        rMenuBar                128            /* application's menu bar */
  117.  
  118. #define        mApple                    128            /* Apple menu */
  119. #define        iAbout                    1
  120.  
  121. #define        mFile                    129            /* File menu */
  122. #define        iNew                    1
  123. #define        iClose                    4
  124. #define        iQuit                    12
  125.  
  126. #define        mEdit                    130            /* Edit menu */
  127. #define        iUndo                    1
  128. #define        iCut                    3
  129. #define        iCopy                    4
  130. #define        iPaste                    5
  131. #define        iClear                    6
  132.  
  133. /* kDITop and kDILeft are used to locate the Disk Initialization dialogs. */
  134. #define        kDITop                    0x0050
  135. #define        kDILeft                    0x0070
  136.  
  137.  
  138. /* Globs */
  139. SysEnvRec            gMac;                    /* set up by Initialize */
  140. Boolean                gHasWaitNextEvent;        /* set up by Initialize */
  141. Boolean                gInBackground;            /* maintained by Initialize and DoEvent */
  142. XCallParamPtr        gXPBPBPtr;                /* structure for Phase 2 NBP lookups       */
  143.                                             /* needs to be global for failure handling */
  144.  
  145.  
  146. ListHandle    gList;                    /* the list to be filled with zone names */
  147.  
  148. extern void _DataInit();
  149.  
  150. /*     globals added for C sample use as the Pascal
  151.     example used those horrid :-) nested procedures! */
  152. ATPPBPtr    gATPPBPtr;    /* the parameter block for GetZoneList call */
  153. Ptr            gZones;     /* the data buffer for GetZoneList call */
  154. DialogPtr    gErrDlg;    /* Dialog used for displaying zone list */
  155.  
  156.  
  157. /*    Check to see if a given trap is implemented. This is only used by the
  158.     Initialize routine in this program, so we put it in the Initialize segment.
  159.     The recommended approach to see if a trap is implemented is to see if
  160.     the address of the trap routine is the same as the address of the
  161.     Unimplemented trap. */
  162. /*    1.02 - Needs to be called after call to SysEnvirons so that it can check
  163.     if a ToolTrap is out of range of a pre-MacII ROM. */
  164.  
  165. #pragma segment Initialize
  166. Boolean TrapAvailable(tNumber,tType)
  167.     short        tNumber;
  168.     TrapType    tType;
  169. {
  170.     if ( ( tType == (unsigned char) ToolTrap ) &&
  171.         ( gMac.machineType > envMachUnknown ) &&
  172.         ( gMac.machineType < envMacII ) ) {        /* it's a 512KE, Plus, or SE */
  173.         tNumber = tNumber & 0x03FF;
  174.         if ( tNumber > 0x01FF )                    /* which means the tool traps */
  175.             tNumber = _Unimplemented;            /* only go to 0x01FF */
  176.     }
  177.     return NGetTrapAddress(tNumber, tType) != NGetTrapAddress(_Unimplemented, ToolTrap);
  178. } /*TrapAvailable*/
  179.  
  180.  
  181. #pragma segment Main
  182. void FailOSErrMsg(result, message)
  183.     short    result;
  184.     short    message;
  185. {
  186.     if (result != noErr)
  187.         Failure(result, message);
  188. } /* SignalOSErrMsg */
  189.  
  190.  
  191. #pragma segment Main
  192. void FailnilMsg(p, message)
  193.     Ptr        p;
  194.     short    message;
  195. {
  196.     if (p == nil)
  197.         Failure(memFullErr, message);
  198. } /* FailNILMsg */
  199.  
  200.  
  201. #pragma segment Main
  202. void AlertUser(error, message)
  203.  
  204. /* Display an alert to inform the user of an error. Message acts as an
  205.  index into a STR# resource of error messages. if no message is given,
  206.  i.e. = 0, then use a standard message. if error is not noErr then
  207.  display it as well. */
  208.  
  209.     short    error;
  210.     long    message;
  211. {
  212.     Str255    msg1, msg2;
  213.     short    itemHit;
  214.  
  215.     if (message <= 0L)  message = eStandardErr;
  216.     GetIndString(msg1, sErrStrings, message);
  217.     if (error == noErr)
  218.         msg2[0] = '';
  219.     else
  220.         NumToString(error, msg2);
  221.     ParamText(msg1, msg2, "\p", "\p");
  222.     itemHit = Alert(rUserAlert, nil);
  223. } /* AlertUser */
  224.  
  225.  
  226. #pragma segment Main
  227. Boolean IsDAWindow(window)
  228.     WindowPtr    window;
  229. {
  230.     if (window == nil)
  231.         return (false);
  232.     else    /* DA windows have negative windowKinds */
  233.         return ((WindowPeek) window)->windowKind < 0;
  234. } /* IsDAWindow */
  235.  
  236.  
  237. #pragma segment Main
  238. Boolean IsAppWindow(window)
  239.     WindowPtr    window;
  240. {
  241.     short        windowKind;
  242.  
  243.     if ( window == nil )
  244.         return false;
  245.     else {    /* application windows have windowKinds >= userKind (8) or dialogKind (2) */
  246.         windowKind = ((WindowPeek) window)->windowKind;
  247.         return (windowKind >= userKind) || (windowKind == dialogKind);
  248.     }
  249. } /* IsAppWindow */
  250.  
  251.  
  252. #pragma segment Main
  253. void ZoneListCleanUp()
  254. {
  255.     if (gATPPBPtr != nil)
  256.         DisposePtr((Ptr)gATPPBPtr);            /* get rid of pb block */
  257.     if (gZones != nil)
  258.         DisposePtr(gZones);                    /* and buffer */
  259. } /* ZoneListCleanUp */
  260.  
  261.  
  262. #pragma segment Main
  263. pascal void HandleZoneListErr(short error, long message)
  264. {
  265.     #pragma    unused (error, message)
  266.  
  267.     ZoneListCleanUp();                        /* get rid of allocated junk */
  268. } /* HandleZoneListErr */
  269.  
  270.  
  271. #pragma segment Main
  272. void BuildZoneList()
  273.  
  274. /*
  275.  *    Create the list of zones on the network. Find a bridge to talk to , if one is
  276.  *     present, then ask it for zone names. Add the names to the list in the dialog.
  277.  */
  278.  
  279. {
  280.     BDSElement    dBDS;                /* the BDS for GetZoneList call */
  281.     Ptr            dCurr;                /* the data buffer for GetZoneList call */
  282.     short        dIndex, dCount;
  283.     short        ignore;
  284.     Cell        cSize;
  285.     FailInfo    fi;
  286.     short        nodeNetAddress, bridgeNode;
  287.  
  288.     gATPPBPtr = nil;                                            /* init some important variables*/
  289.     gZones = nil;
  290.  
  291.     CatchCFailures(&fi, HandleZoneListErr);
  292.  
  293.     gATPPBPtr = (ATPPBPtr)NewPtr(sizeof(ATPParamBlock));
  294.     FailnilMsg(gATPPBPtr, eNoMemory);
  295.     gZones = NewPtr(kZonesSize);
  296.     FailnilMsg(gZones, eNoMemory);
  297.     dBDS.buffSize = kZonesSize;                                    /* set up BDS */
  298.     dBDS.buffPtr = gZones;
  299.  
  300.     gATPPBPtr->ATPatpFlags = 0;
  301.  
  302.     /*
  303.      *    get network address of node & node ID of bridge (if any)
  304.      */
  305.     FailOSErrMsg(GetNodeAddress(&ignore, &nodeNetAddress), eAppleTalk);
  306.     bridgeNode = GetBridgeAddress();
  307.  
  308.     /*
  309.      * test to see if bridge node fails.  If so, no internet.
  310.      */
  311.     if (bridgeNode == 0)
  312.         Failure(0, eNoZones);                                    /* bail if no zones present */
  313.  
  314.     gATPPBPtr->ATPaddrBlock.aNet = nodeNetAddress;
  315.     gATPPBPtr->ATPaddrBlock.aNode = bridgeNode;                    /* get node of bridge */
  316.     gATPPBPtr->ATPaddrBlock.aSocket = kZIPSocket;                /* the socket we want */
  317.     gATPPBPtr->ATPreqLength = 0;
  318.     gATPPBPtr->ATPreqPointer = nil;
  319.     gATPPBPtr->ATPbdsPointer = (Ptr) &dBDS;
  320.     gATPPBPtr->ATPnumOfBuffs = 1;
  321.     gATPPBPtr->ATPtimeOutVal = kATPTimeOutVal;
  322.     gATPPBPtr->ATPretryCount = kATPRetryCount;
  323.  
  324.     dIndex = 1;
  325.     dCount = 0;
  326.     SetPt(&cSize, 0, 0);                                                /* we always stuff into first */
  327.  
  328.     do {
  329.         gATPPBPtr->ATPuserData = kGZLCall + dIndex;                        /* indicate GetZoneList request */
  330.         FailOSErrMsg(PSendRequest(gATPPBPtr, false), eAppleTalk);        /* send sync request */
  331.  
  332.         dCount = dCount + dBDS.userBytes & kZoneCount;                    /* find out how many returned */
  333.         dCurr = gZones;                                                    /* put current pointer at start */
  334.         do {                                                            /* get each zone */
  335.             ignore = LAddRow(1, 0, gList);                                /* create new cell at start */
  336.             LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList);    /* stuff in zone */
  337.             dCurr = (Ptr)(dCurr + *dCurr + 1 );                            /* bump up current pointer */
  338.             dIndex = dIndex + 1;                                        /* increment which zone */
  339.         } while(! (dIndex > dCount));
  340.  
  341.     } while ((dBDS.userBytes & kMoreZones) == 0);                /*     keep going until none left */
  342.  
  343.     ZoneListCleanUp();
  344.  
  345.     Success(&fi);
  346. } /* BuildZoneList */
  347.  
  348.  
  349. #pragma segment Main
  350. void ZoneListCleanUpPhase2()
  351. {
  352.     if (gXPBPBPtr != nil)
  353.         DisposePtr((Ptr)gXPBPBPtr);            /* get rid of pb block */
  354.     if (gZones != nil)
  355.         DisposePtr(gZones);                    /* and buffer */
  356. } /* ZoneListCleanUpPhase2 */
  357.  
  358. #pragma segment Main
  359. void BuildZoneListPhase2()
  360.  
  361. /*     Create the list of zones on the network. Find a bridge to talk to , if one is
  362.      present, then ask it for zone names. Add the names to the list in the dialog.    */
  363.  
  364. {
  365.     Ptr            dCurr;                /* the data buffer for GetZoneList call */
  366.     short        dIndex, dCount;
  367.     short        ignore;
  368.     Cell        cSize;
  369.     FailInfo    fi;
  370.  
  371.     short        xppDriverRefNum;
  372.  
  373.     gXPBPBPtr = nil;                                            /* init some important variables*/
  374.     gZones = nil;
  375.  
  376.     CatchCFailures(&fi, HandleZoneListErr);
  377.  
  378.     /* Get network address of bridge.  If zero, no internet. */
  379.     if (GetBridgeAddress() == 0)
  380.         Failure(0, eNoZones);                                    /* bail if no zones present */
  381.  
  382.     /* get a hold of the XPP driver reference number-this is the safest way */
  383.     FailOSErrMsg(OpenDriver("\p.XPP", &xppDriverRefNum), eAppleTalk);
  384.  
  385.     gXPBPBPtr = (XCallParamPtr)NewPtr(sizeof(XCallParam));
  386.     FailnilMsg(gXPBPBPtr, eNoMemory);
  387.     gZones = NewPtr(kZonesSize);
  388.     FailnilMsg(gZones, eNoMemory);
  389.  
  390.     gXPBPBPtr->zipInfoField[0] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  391.     gXPBPBPtr->zipInfoField[1] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  392.     gXPBPBPtr->zipLastFlag = 0;
  393.  
  394.     gXPBPBPtr->ioRefNum = xppDriverRefNum;
  395.     gXPBPBPtr->csCode = xCall;
  396.     gXPBPBPtr->xppSubCode = zipGetZoneList;
  397.     gXPBPBPtr->xppTimeout = kATPTimeOutVal;
  398.     gXPBPBPtr->xppRetry = kATPRetryCount;
  399.     gXPBPBPtr->zipBuffPtr = (Ptr) gZones;
  400.  
  401.     dIndex = 1;
  402.     dCount = 0;
  403.     SetPt(&cSize, 0, 0);                                                /* we always stuff into first */
  404.  
  405.     do {
  406.         FailOSErrMsg(PBControl((ParmBlkPtr) gXPBPBPtr, false), eAppleTalk);        /* send sync control call */
  407.  
  408.         dCount = dCount + gXPBPBPtr->zipNumZones;                        /* find out how many returned */
  409.         dCurr = gZones;                                                    /* put current pointer at start */
  410.         do {                                                            /* get each zone */
  411.             ignore = LAddRow(1, 0, gList);                                /* create new cell at start */
  412.             LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList);    /* stuff in zone */
  413.             dCurr = (Ptr)(dCurr + *dCurr + 1 );                            /* bump up current pointer */
  414.             dIndex = dIndex + 1;                                        /* increment which zone */
  415.         } while(! (dIndex > dCount));
  416.  
  417.     } while (gXPBPBPtr->zipLastFlag == 0);                /*     keep going until none left */
  418.  
  419.     ZoneListCleanUpPhase2();
  420.  
  421.     Success(&fi);
  422. } /* BuildZoneList */
  423.  
  424. #pragma segment Main
  425. pascal void ZoneListDraw(dlg, item)
  426.     DialogPtr    dlg;
  427.     short        item;
  428. {
  429.  
  430. /* The user item void for the zone list user item and default
  431.  box user item in the dialog. Draw the list and the frame that goes with it.
  432.  Draw the default box around the OK button */
  433.  
  434.     GrafPtr     port;
  435.     short        kind;
  436.     Handle        h;
  437.     Rect        r;
  438.     PenState    ps;
  439.  
  440.     GetPort(&port);                                        /* save old port */
  441.     SetPort(dlg);                                        /* make dialog port */
  442.     switch (item) {
  443.         case dZoneList:
  444.             LUpdate(dlg->visRgn, gList);                /* re-draw list */
  445.             GetDialogItem(dlg, dZoneList, &kind, &h, &r);
  446.             InsetRect(&r, kListInset, kListInset);
  447.             FrameRect(&r);                                /* re-draw frame */
  448.             break;
  449.         case dDefault:
  450.             GetDialogItem(dlg, dDefault, &kind, &h, &r);
  451.             GetPenState(&ps);
  452.             PenNormal();                                /* always be on the defensive */
  453.             PenSize(3, 3);
  454.             InsetRect(&r, -4, -4);
  455.             FrameRoundRect(&r, 16, 16);                    /* draw default box */
  456.             SetPenState(&ps);
  457.             break;
  458.         }
  459.     SetPort(port);                                        /* restore old port */
  460. } /* ZoneListDraw */
  461.  
  462.  
  463. #pragma segment Main
  464. pascal Boolean ListFilter (dlg, event, item)
  465.     DialogPtr    dlg;
  466.     EventRecord    *event;
  467.     short        *item;
  468. {
  469.  
  470. /*    Passed as parameter to ModalDialog. Handle key presses and mouse clicks
  471.        from the user. Do all the right default actions since we override them
  472.      by virtue of our existence.    */
  473.  
  474.     GrafPtr        port;
  475.     Point        loc;
  476.     short        kind;
  477.     Handle        h;
  478.     Rect        r;
  479.     Boolean        ignore;
  480.     char        key;
  481.     long         finalTicks;
  482.  
  483.     Boolean        returnValue;
  484.  
  485.     returnValue = false;                                            /*    always default false */
  486.  
  487.     switch (event->what) {
  488.         case keyDown:                                                 /*    check for <cr> or <enter> */
  489.         case autoKey:
  490.             key = (char) event->message;
  491.             if (key == kCR || key == kENTER) {                        /*    it was a <cr> or <enter> */
  492.                 GetDialogItem(dlg, ok, &kind, &h, &r);
  493.                 HiliteControl((ControlHandle)h, kHilite);
  494.                 Delay(kHiliteDelay, &finalTicks);
  495.                 HiliteControl((ControlHandle)h, kDeHilite);
  496.                 returnValue = true;                                    /*    so we handle it */
  497.                 *item = 1;                                            /*    and make the first item hit */
  498.                 }
  499.             break;
  500.         case mouseDown:                                             /*    we want mouseDowns */
  501.             GetPort(&port);
  502.             SetPort(dlg);
  503.             loc = event->where;
  504.             GlobalToLocal(&loc);                                    /*    find where clicked */
  505.             GetDialogItem(dlg, dZoneList, &kind, &h, &r);                /*    get rect for list */
  506.             if (PtInRect(loc, &r)) {                                /*    if clicked inside… */
  507.                 returnValue = true;                                    /*    we take care of it */
  508.                 ignore = LClick(loc, event->modifiers, gList);        /*    by passing click to list */
  509.                 }
  510.             SetPort(port);
  511.             break;
  512.         }
  513.     return (returnValue);
  514. } /* ListFilter */
  515.  
  516.  
  517. #pragma segment Main
  518. void CleanUp_DoZoneList()
  519. {
  520.     if (gList != nil)
  521.         LDispose(gList);                                    /*    get rid of list */
  522.     if (gErrDlg != nil)
  523.         DisposeDialog(gErrDlg);                                /*    get rid of dialog */
  524. } /* CleanUp_DoZoneList */
  525.  
  526.  
  527. #pragma segment Main
  528. pascal void HandleErr_DoZoneList(short error, long message)
  529. {
  530.     #pragma    unused (error, message)
  531.  
  532.     CleanUp_DoZoneList();                                /*    release junk */
  533. } /* HandleErr_DoZoneList */
  534.  
  535.  
  536. #pragma segment Main
  537. void DoZoneList()
  538.  
  539. /*    Put up a modal dialog that shows a list of the zones on the net. Create the dialog
  540.  and list, call BuildZoneList to fill it, then wait for the user to click OK. */
  541.  
  542. {
  543.     DialogPtr    dlg;
  544.     short        item, kind;
  545.     Handle        h;
  546.     Rect        r, rView, dataBounds;
  547.     Cell        cSize;
  548.     FailInfo    fi;
  549.     short        hor, ver;
  550.     ModalFilterUPP mfUPP;
  551.  
  552.     gList = nil;                                            /*    init some important variables */
  553.     dlg = nil;
  554.  
  555.     CatchCFailures(&fi, HandleErr_DoZoneList);
  556.  
  557.     dlg = GetNewDialog(rZoneDialog, nil, (WindowPtr)-1);            /*    create dialog */
  558.     SetPort(dlg);
  559.  
  560.     gErrDlg = dlg;
  561.  
  562.     FailnilMsg(dlg, eNoMemory);
  563.  
  564.     /*    We center the dialog horizontally and position it vertically one-third the
  565.      distance from the menu bar to the bottom of the main device. We do not
  566.      check for the dialog extending past the bottom of the device because we
  567.      know the dialog is not that big. You may wish to make that check. */
  568.  
  569.     hor = dlg->portRect.right - dlg->portRect.left;
  570.     ver = dlg->portRect.bottom - dlg->portRect.top;
  571.  
  572.     hor = ((qd.screenBits.bounds.right - qd.screenBits.bounds.left) - hor) / 2;
  573.     ver = (((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - ver - GetMBarHeight()) / 3) + GetMBarHeight();
  574.  
  575.     MoveWindow(dlg, hor, ver, false);
  576.  
  577.     GetDialogItem(dlg, dDefault, &kind, &h, &r);
  578.     SetDialogItem(dlg, dDefault, kind, (Handle) ZoneListDraw, &r);
  579.     GetDialogItem(dlg, dZoneList, &kind, &h, &r);
  580.     SetDialogItem(dlg, dZoneList, kind, (Handle) ZoneListDraw, &r);        /*    connect drawing void */
  581.     rView = r;
  582.     rView.right -= kScrollBarWidth;                            /*    adjust rectangle for scroll */
  583.     SetRect(&dataBounds, 0, 0, 1, 0);                        /*    init to one-wide list */
  584.     SetPt(&cSize, 0, 0);
  585.     gList = LNew(&rView, &dataBounds, cSize, 0, (WindowPtr)dlg,
  586.                     false, false, false, true);                /*    create with vertical scroll */
  587.     FailnilMsg(gList, eNoMemory);
  588.  
  589.     /* changes for Phase 2 - pvh 8/6/89 */
  590.     /* this is the easiest check for Phase 2's existence */
  591.     if(gMac.atDrvrVersNum >= 53)
  592.         BuildZoneListPhase2();                                    /*    put the stuff into the list */
  593.     else
  594.         BuildZoneList();                                        /*    put the stuff into the list */
  595.  
  596.     SetPt(&cSize, 0, 0);
  597.     LSetSelect(true, cSize, gList);                            /*    select the first guy */
  598.     LSetDrawingMode(true, gList);                                    /*    turn on the list */
  599.     ShowWindow(dlg);                                        /*    turn on the dialog */
  600.  
  601.     mfUPP = NewModalFilterProc(ListFilter);
  602.     do {
  603.         ModalDialog(mfUPP, &item);    /*    accept events */
  604.     } while (item != ok);                                    /*    until he presses 'ok' */
  605.     DisposeRoutineDescriptor(mfUPP);
  606.  
  607.     CleanUp_DoZoneList();
  608.  
  609.     Success(&fi);
  610. } /* DoZoneList */
  611.  
  612.  
  613. #pragma segment Main
  614. Boolean DoCloseWindow(window)
  615.     WindowPtr    window;
  616. {
  617.     Boolean     functionValue = true;
  618.  
  619.     if (IsDAWindow(window))
  620.         CloseDeskAcc((short) ((WindowPeek)window)->windowKind);
  621.     if (IsAppWindow(window))
  622.         CloseWindow(window);
  623.  
  624.     return(functionValue);
  625. } /* DoCloseWindow */
  626.  
  627.  
  628. #pragma segment Initialize
  629. pascal void HandleErr_Initialize(error, message)
  630.     short    error;
  631.     long    message;
  632. {
  633.         if (error > 0)
  634.             AlertUser(0, error);
  635.         else
  636.             AlertUser(error, message);
  637.         ExitToShell();
  638. } /* HandleErr_Initialize */
  639.  
  640.  
  641. #pragma segment Initialize
  642. void Initialize()
  643. {
  644.     Handle            menuBar;
  645.     OSErr            ignoreError;
  646.     long            total, contig;
  647.     Boolean            ignoreResult;
  648.     EventRecord        event;
  649.     short            count;
  650.     FailInfo        fi;
  651.  
  652.     gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
  653.     gInBackground = false;
  654.  
  655.     InitGraf(&qd.thePort);
  656.     InitFonts();
  657.     InitWindows();
  658.     InitMenus();
  659.     TEInit();
  660.     InitDialogs(nil);
  661.     InitCursor();
  662.  
  663.     /* get MultiFinder started */
  664.     for (count=1;count<3;count++)
  665.         ignoreResult = EventAvail(everyEvent, &event);
  666.  
  667.     CatchCFailures(&fi, HandleErr_Initialize);
  668.  
  669.     FailOSErrMsg(MPPOpen(), eAppleTalk);
  670.     FailOSErrMsg(ATPLoad(), eAppleTalk);
  671.  
  672.     ignoreError = SysEnvirons(kSysEnvironsVersion, &gMac);
  673.     if (gMac.machineType < 0)
  674.         Failure(0, eWrongMachine);
  675.  
  676.     if (GetApplLimit() - ApplicationZone() < kMinHeap)
  677.         Failure(0, eSmallSize);
  678.  
  679.     PurgeSpace(&total, &contig);
  680.     if (total < kMinSpace)
  681.         Failure(0, eNoMemory);
  682.  
  683.     menuBar = GetNewMBar(rMenuBar);                /*    read menus into menu bar */
  684.     FailnilMsg(menuBar, eNoMemory);
  685.  
  686.     SetMenuBar(menuBar);                        /*    install menus */
  687.     DisposeHandle(menuBar);
  688.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');        /*    add DA names to Apple menu */
  689.     DrawMenuBar();
  690.  
  691.     Success(&fi);
  692. } /* Initialize */
  693.  
  694.  
  695. #pragma segment Main
  696. void Terminate()
  697. {
  698.     WindowPtr    aWindow;
  699.     Boolean        closed;
  700.  
  701.     closed = true;
  702.     do {
  703.         aWindow = FrontWindow();                /*    get the current front window */
  704.         if (aWindow != nil)
  705.             closed = DoCloseWindow(aWindow);    /*    close this window */
  706.     } while ((closed) && (aWindow != nil));        /*    do all windows */
  707.     if (closed)
  708.         ExitToShell();                            /*    exit if no cancellation */
  709. } /* Terminate */
  710.  
  711.  
  712. #pragma segment Main
  713. void AdjustMenus()
  714. {
  715.     WindowPtr    window;
  716.     MenuHandle    menu;
  717.  
  718.     window = FrontWindow();
  719.  
  720.     menu = GetMenuHandle(mFile);
  721.     if (IsDAWindow(window))                        /*    we can allow desk accessories to be closed from the menu */
  722.         EnableItem(menu, iClose);
  723.     else
  724.         DisableItem(menu, iClose);                /*    but not our traffic light window */
  725.  
  726.     menu = GetMenuHandle(mEdit);
  727.     if (IsDAWindow(window)) {                    /*    a desk accessory might need the edit menu */
  728.         EnableItem(menu, iUndo);
  729.         EnableItem(menu, iCut);
  730.         EnableItem(menu, iCopy);
  731.         EnableItem(menu, iPaste);
  732.         EnableItem(menu, iClear);
  733.         }
  734.     else {                                        /*    but we know we do not */
  735.         DisableItem(menu, iUndo);
  736.         DisableItem(menu, iCut);
  737.         DisableItem(menu, iCopy);
  738.         DisableItem(menu, iClear);
  739.         DisableItem(menu, iPaste);
  740.         }
  741. } /* AdjustMenus */
  742.  
  743.  
  744. pascal void HandleMenu(short error, long message)
  745. {
  746.     #pragma    unused (error, message)
  747.  
  748.     HiliteMenu(0);                                /*    unhighlight what MenuSelect (or MenuKey) hilited */
  749. } /* HandleMenu */
  750.  
  751.  
  752. #pragma segment Main
  753. void DoMenuCommand(menuResult)
  754.     long    menuResult;
  755. {
  756.     short        menuID;                            /*    the resource ID of the selected menu */
  757.     short        menuItem;                        /*    the item number of the selected menu */
  758.     short        itemHit;
  759.     Str255        daName;
  760.     short        daRefNum;
  761.     Boolean        handledByDA    ;
  762.     Boolean        ignore;
  763.     FailInfo    fi;
  764.  
  765.     CatchCFailures(&fi, (HandlerFuncPtr) HandleMenu);
  766.  
  767.     menuID = HiWord(menuResult);                            /*    use built-ins (for efficiency)... */
  768.     menuItem = LoWord(menuResult);                        /*    to get menu item number and menu number */
  769.     switch (menuID) {
  770.         case mApple:
  771.             switch (menuItem) {
  772.                 case iAbout:                            /*    bring up alert for About */
  773.                     itemHit = Alert(rAboutAlert, nil);
  774.                     break;
  775.                 default:                                /*    all non-About items in this menu are DAs */
  776.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  777.                     daRefNum = OpenDeskAcc(daName);
  778.                     break;
  779.                 }
  780.             break;
  781.         case mFile:
  782.             switch (menuItem) {
  783.                 case iNew:
  784.                     DoZoneList();
  785.                     break;
  786.                 case iClose:
  787.                     ignore = DoCloseWindow(FrontWindow());
  788.                     break;
  789.                 case iQuit:
  790.                     Terminate();
  791.                     break;
  792.                 }
  793.             break;
  794.         case mEdit:                                    /*    call SystemEdit for DA editing & Multifinder */
  795.             handledByDA = SystemEdit(menuItem-1);    /*    since we don't do any editing */
  796.             break;
  797.         }
  798.  
  799.     HiliteMenu(0);                                    /*    cleanup */
  800.  
  801.     Success(&fi);
  802. } /* DoMenuCommand */
  803.  
  804.  
  805. #pragma segment Main
  806. pascal void HandleErr_DoEvent(error, message)
  807.     short    error;
  808.     long    message;
  809. {
  810.     if (error > 0)
  811.         AlertUser(0, error);
  812.     else
  813.         AlertUser(error, message);
  814.     ExitToShell();
  815. } /* HandleErr_DoEvent */
  816.  
  817.  
  818. #pragma segment Main
  819. void DoEvent(event)
  820.     EventRecord    event;
  821. {
  822.     short        part;
  823.     WindowPtr    window;
  824.     char        key;
  825.     FailInfo    fi;
  826.     Point        aPoint;
  827.     OSErr        err;
  828.  
  829.     CatchCFailures(&fi, (HandlerFuncPtr) HandleErr_DoEvent);
  830.  
  831.     switch (event.what) {
  832.         case mouseDown:
  833.             part = FindWindow(event.where, &window);
  834.             switch (part) {
  835.                 case inMenuBar:                            /*    process the menu command */
  836.                     AdjustMenus();
  837.                     DoMenuCommand(MenuSelect(event.where));
  838.                     break;
  839.                 case inSysWindow:                        /*    let the system handle the mouseDown */
  840.                     SystemClick(&event, window);
  841.                     break;
  842.                 case inContent:
  843.                     break;
  844.                 case inDrag:
  845.                     break;
  846.                 case inGrow:
  847.                     break;
  848.                 case inZoomIn:
  849.                 case inZoomOut:
  850.                     break;
  851.                 }
  852.             break;
  853.         case keyDown:                                     /*    check for menukey equivalents */
  854.         case autoKey:
  855.             key = event.message & charCodeMask;
  856.             if (event.modifiers & cmdKey) {                /*    Command key down */
  857.                 if (event.what == keyDown) {
  858.                     AdjustMenus();                        /*    enable/disable/check menu items properly */
  859.                     DoMenuCommand(MenuKey(key));
  860.                     }
  861.                 }
  862.             break;
  863.         /*    call DoActivate with the window and... */
  864.         case activateEvt:
  865.             break;
  866.         case updateEvt:
  867.             break;
  868.         /* It is not a bad idea to at least call DIBadMount in response
  869.          to a diskEvt, so that the user can format a floppy. */
  870.         case diskEvt:
  871.             if (HiWord(event.message) != noErr) {
  872.                 SetPt(&aPoint, kDILeft, kDITop);
  873.                 err = DIBadMount(aPoint, event.message);
  874.             }
  875.         case kOSEvent:
  876.             switch ((event.message >> 24) & 0x0FF) {     /* high byte of message */
  877.                 case kSuspendResumeMessage:
  878.                     gInBackground = event.message & kResumeMask;
  879.                     break;
  880.                 }
  881.             break;
  882.         }
  883.     Success(&fi);
  884. } /* DoEvent */
  885.  
  886.  
  887. #pragma segment Main
  888. void EventLoop()
  889. {
  890.     RgnHandle    cursorRgn;
  891.     Boolean        gotEvent;
  892.     EventRecord    event;
  893.  
  894.     cursorRgn = NewRgn();            /*    we’ll pass WNE an empty region the 1st time thru */
  895.  
  896.     do {
  897.         if (gHasWaitNextEvent)        /*    put us 'asleep' forever under Multifinder */
  898.             gotEvent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursorRgn);
  899.         else {
  900.             SystemTask();            /*    must be called if using GetNextEvent */
  901.             gotEvent = GetNextEvent(everyEvent, &event);
  902.             }
  903.         if (gotEvent) {
  904.             DoEvent(event);
  905.             }
  906.     } while (true);                    /*    loop forever; we quit through an ExitToShell */
  907. } /* EventLoop */
  908.  
  909.  
  910. #pragma segment Main
  911. void main()
  912. {
  913.     UnloadSeg(_DataInit);            /*    note that _DataInit must not be in Main! */
  914.     MaxApplZone();                    /*    expand the heap so code segments load at the top */
  915.  
  916.     InitUFailure();
  917.  
  918.     Initialize();                    /* initialize the program */
  919.     UnloadSeg(Initialize);            /* note that Initialize must not be in Main! */
  920.  
  921.     EventLoop();                    /* call the main event loop */
  922. } /* main */
  923.